iT邦幫忙

2024 iThome 鐵人賽

DAY 13
2
Modern Web

欸你是要進 Vue 了沒?系列 第 13

欸你是要進 Vue 了沒? - Day13:Vue 你怎麼 DOM 起來了?都學到這了依舊沒辦法繞過的 JS 原生 Proxy 概念

  • 分享至 

  • xImage
  •  

前兩天認識到 ref 綁定「物件」、Vue 會將其包裝成一個 Proxy 物件的時候,點了官方文件放的 MDN,發現完全看不懂,想說沒關係~好像可以先無視它~結果很快的發現沒辦法銜接到接下來要學的 reactive⋯⋯
真的完全 GG(然後小裁判在旁邊緊盯著 👀)
/images/emoticon/emoticon70.gif

Proxy 你到底是什麼啦齁!

定義

MDN:Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。

翻譯蒟蒻:Proxy 是一個代理物件,功能是可以創建一個「對目標物件的代理」,去操作攔截和自定義行為(例如存取屬性、更改值等等)。

語法

Proxy 是用 new 建構出來的,語法為:

new Proxy(target, handler)
  • target 參數:要拿來使用 Proxy 包裝的「目標物件」。
  • handler 參數:也是一個物件,其中通常會定義「函式」屬性,也就是在操作這個代理的時候,要對目標物件執行的行為。

Step1:建立代理物件

行為:定義代理物件其中的參數(也就是上述說的 targethandler

const target = 某個物件;
const ref = new Proxy(target, {
  get: function(target, property){
  return 自定義的資料;
  }
});

以上範例做了:

  • 將 某個物件 定義為 target 變數,傳入 new Proxy 作為 target 參數。
  • 定義 handler 參數 為 { get: funciton(target, property){ return 自定義的資料; } }
  • 將代理物件存進變數 ref

Step2:使用代理物件

行為:

  1. 存取代理物件屬性
  2. 執行 handler
  3. 拿到 return 的自定義資料
console.log(ref.target1);

以上範例做了:對 ref 物件存取 target1 屬性,因此執行 handler 中定義的 get 函式,可拿到 target1 return 的自定義資料。

為何需要你?

我們以一個例子來看:

const name = {
  firstName: "Jami",
  lastName: "Guo",
};
console.log(`名字`, name.firstName);
console.log(`全名`, name.firstName + name.lastName);
</script>

這裡定義了 name 物件,而 console.log 反映了我們可能會有這兩件事情想做:

  1. 我要印出名字(firstName)
  2. 我要印出全名(firstName+lastName)

然而~我們可以用 Proxy 物件來包裝這樣的需求!

範例一

const name = {
  firstName: "Jami",
  lastName: "Guo",
};

const ref = new Proxy(name, {
  get: function (target, property) {
    if (property === "fullName") {
      return target.firstName + "" + target.lastName;
    }
    return target[property];
  }
});

console.log(ref.fullName);
console.log(ref.firstName);

上述我們做了什麼事:

  1. 建立代理物件,定義代理物件其中的參數
  • 定義 target 目標物件
const name = {
  firstName: "Jami",
  lastName: "Guo",
};
  • 定義 handler 操作行為
{
  get: function (target, property) {
    if (property === "fullName") {
      return target.firstName + " " + target.lastName;
    }
    return target[property];
  }
}
  1. 把代理物件存進變數 ref
  2. 執行 ref 並存取屬性 fullName
console.log(ref.fullName);

這將會把 fullName 引數帶入 property,判斷式中條件成立,所以將會執行 return target.firstName + "" + target.lastName;,印出的結果會是 JamiGuo

  1. 執行代理物件 ref 並存取屬性 firstName
console.log(ref.firstName);

這將會把 firstName 引數帶入 property,判斷式中條件不成立,所以將會執行 return target[property];,也就是 target[firstName],印出的結果會 Jami

瀏覽器上執行結果:
https://ithelp.ithome.com.tw/upload/images/20240926/20169139ka1gDo0TdD.png

範例二

來看個更實際的例子!

我們有個物件中存放了身高、體重,期望在執行時就可以做到印出身高、體重或 BMI。
我們可以這樣寫~

const personData = {
  height: '1.65',
  weight: 99.9
}

const personProxy = new Proxy(personData, {
  get: function (target, property) {
    if (property === "bmi") {
      return personData.weight / (personData.height ** 2);
    }
    return target[property]
  }
})

console.log('BMI', personProxy.bmi);
console.log('身高', personProxy.height);
console.log('體重', personProxy.weight);

property === "bmi" 的時候,就 return 了我們定義的算 BMI 的語法,!== 的時候,就 return target[property],用 物件[屬性] 取得需要的值(身高或體重)。

於是我們將會印出:
https://ithelp.ithome.com.tw/upload/images/20240926/20169139VLx3G7bcjA.png

小結

我們將學習概念回到 Vue 響應式系統⋯⋯
當我們通過 ref 存取一個物件的屬性時,背後其實是運用了 Proxy 的概念,而 Proxy 代理物件,可透過「攔截」機制、配合設置的 handler 物件,自定義對目標物件的行為,更新介面。

明天我們繼續說說 Vue 響應式基礎的另外一個語法 reactive

硬要小心得分享

學這裡的時候,看了好多文件都不懂,在想說可能換個方式才會懂了~想聽人講解,所以到 youtube 找資料,是最後看了 彭彭這部影片 才覺得有清楚理解的(老師的頻道是我在一年半前學前端的啟蒙 XDDDD)

也想分享一下之前 Chris 在幫我 code review 的時候他提到的想法:

學習的時候,必須知道:具備什麼條件怎麼會讓自己懂。

可能是:先知道這件事情、再小規模練習、再了解之外的特性、再去組合跟什麼很像,然後可能先放著、某天就會突然懂了之類的。

大學的時候,因為要學想學的東西,當想盡辦法要學起來的時候,就會去研究怎樣才學的起來。
需要練習嗎?哪裡我不懂?這件事是不是用看的學會?經過什麼樣的體會才學得會?

所以得想辦法拿到那個體會,學會的感覺才會明顯。

而這件事也是得一直有意識地去做才行~~

謝天謝地,繼續加油耶比
/images/emoticon/emoticon42.gif

範例 code ⬇️

https://github.com/Jamixcs/2024iThome-jamixcs/tree/main/src/components/day13

參考資料


上一篇
欸你是要進 Vue 了沒? - Day12:Vue 你怎麼 DOM 起來了?響應式基礎從 ref 開始(下)
系列文
欸你是要進 Vue 了沒?13
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言